package pl.edu.agh.mr.nb.gui;

import com.trolltech.qt.core.QPoint;
import com.trolltech.qt.core.QRect;
import com.trolltech.qt.core.Qt.MouseButton;
import com.trolltech.qt.gui.*;

public class FractalPainter extends QWidget {
	
	public static final int DIMX = 600;
	public static final int DIMY = 600;

	public static final int COLORSNUM = 256;
	private final static int DEPTH = 255; 
    
	public int colors[][] = new int[DIMY][DIMX];
	
	QColor palete[] = new QColor[COLORSNUM];
	
	QRect zoomRect;
	QRect lastZoomRect;
	QPoint startPoint;
	
	boolean isBlocked = false;
	
	
	public Signal2<QPoint, QPoint> zoomedIn = new Signal2<QPoint, QPoint>();
	public Signal0 zoomedOut = new Signal0();
	
    public FractalPainter(QWidget parent) {
        super(parent);
        
        setColorPalete();
    }
    
    public void paintFractal(int fractal[][]) {
    	colors = fractal;
    	QApplication.invokeLater(new Runnable() {
            public void run() {
            	repaint();
            }
        });
    }
    
    public void block() {
    	isBlocked = true;
    }
    
    public void unblock() {
    	isBlocked = false;
    }
    
    private void setColorPalete() {
    	for (int i=0;i<COLORSNUM;i++) {
    		palete[i] = new QColor();
    		int r = (int) (Math.sin(Math.PI * i / DEPTH) * COLORSNUM)-1;
    		if(r < 0) r = 0;
    		int g = (int) (Math.sin(1.5*Math.PI * i / DEPTH) * COLORSNUM)-1;
    		if(g < 0) g = 0;
    		int b = (int) (Math.sin(2.0*Math.PI * i / DEPTH) * COLORSNUM)-1;
    		if(b < 0) b = 0;
    		palete[i].setRgb(r, g, b);
    	}
    }
    
    @Override
    protected void paintEvent(QPaintEvent event) {
    	QPainter painter = new QPainter(this);
    	QRegion reg	= event.region();

    	for(QRect rect : reg.rects()) {
		    for (int i=rect.top();i<=rect.bottom();i++) {
	    		for (int j=rect.left(); j<=rect.right();j++) {
					painter.setPen(palete[colors[i][j]]); // colors[i][j] stores values from range of 0 to 255 
					painter.drawPoint(j,i);
				}
		    }
    	}
    	
    	if (zoomRect != null) {
    		painter.setPen(QColor.green);
    		painter.drawRect(zoomRect);
    	}
        painter.end();
        super.paintEvent(event);
    }
    
    @Override
    protected void mousePressEvent(QMouseEvent event) {
    	if(event.button().equals(MouseButton.LeftButton) && !isBlocked) {
	    	zoomRect = new QRect(event.x(), event.y(), 0, 0);
	    	lastZoomRect = new QRect(event.x(), event.y(), 0, 0);
	    	startPoint = event.pos();	
    	}
    	else if (event.button().equals(MouseButton.RightButton) && !isBlocked) {
    		zoomedOut.emit();
    	}
    	super.mouseReleaseEvent(event);
    }
   
    @Override
    protected void mouseReleaseEvent(QMouseEvent event) {
    	QPoint releasePoint = event.pos();

    	zoomRect = null;
    	lastZoomRect = null;
    	if (startPoint !=null && !releasePoint.equals(startPoint)) {
    		zoomedIn.emit(startPoint, releasePoint);
    	}
    	
    	startPoint = null;
    	super.mouseReleaseEvent(event);
    }
		
    @Override
    protected void mouseMoveEvent(QMouseEvent event) {
	 

    	if(zoomRect != null) {
	    	lastZoomRect.setTopLeft(zoomRect.topLeft());
	    	lastZoomRect.setBottomRight(zoomRect.bottomRight());
	    	zoomRect.setBottomRight(event.pos());
	    	
	    	QRegion reg1 = new QRegion(zoomRect.normalized().x()-1, zoomRect.normalized().y()-1,
	    			zoomRect.normalized().width()+2, zoomRect.normalized().height()+2);
	    	QRegion reg2 = new QRegion(zoomRect.normalized().x()+1, zoomRect.normalized().y()+1,
	    			zoomRect.normalized().width()-2, zoomRect.normalized().height()-2);
	    	final QRegion reg3 = reg1.subtracted(reg2);
	    	
	    	QRegion reg4 = new QRegion(lastZoomRect.normalized().x()-1, lastZoomRect.normalized().y()-1,
	    			lastZoomRect.normalized().width()+2, lastZoomRect.normalized().height()+2);
	    	QRegion reg5 = new QRegion(lastZoomRect.normalized().x()+1, lastZoomRect.normalized().y()+1,
	    			lastZoomRect.normalized().width()-2, lastZoomRect.normalized().height()-2);
	    	final QRegion reg6 = reg4.subtracted(reg5);

	    	QApplication.invokeLater(new Runnable() {
	            public void run() {
	            	repaint(reg3.united(reg6));
	            }
	        });
	    }
    	super.mouseMoveEvent(event);
    }
}
